#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using UTable.Logger;

namespace UTable.Objects.Handlers.Gestures
{
    public class OneContactCustomizedGestureRecognizer : GestureRecognizer
    {
        #region Private Fields

        Point _startPosition;

        List<Point> _gesturePath;

        int _currentContactId;

        long _FingerDownTimeTick;

        UIElement _relativeElement;

        DispatcherTimer _drawTimer;

        private Range _contactNumberRange;

        PhysicsTracker _physicsTracker = new PhysicsTracker();

        #endregion

        #region Private Methods

        //超过最大画线时间
        void _drawTimer_Tick(object sender, EventArgs e)
        {
            if (State == OneContactCustomizedStateType.Proceed)
            {
                if (_drawTimer != null)
                {
                    _drawTimer.Stop();
                    _drawTimer = null;

                    TryRecognize();
                }
            }
            State = OneContactCustomizedStateType.Wait;
        }

        void TryRecognize()
        {            
            if (EnabledGestures.Contains(OneContactCustomizedGestureType.Circle))
            {
                double xSum=0;
                double ySum=0;
                int n=_gesturePath.Count;
                foreach (Point p in _gesturePath)
                {
                    xSum += p.X;
                    ySum += p.Y;
                }
                double xAver = xSum / n;
                double yAver = ySum / n;

                Point o=new Point(xAver,yAver);
                double sum1 = 0;
                double sum2 = 0;

                foreach (Point p in _gesturePath)
                {
                    sum1 += (p - o).Length;
                    sum2 += (p - o).Length * (p - o).Length;
                }

                //double fc = sum2 / n / (sum1 / n) / (sum1 / n) - 1;
                double fc = 1 - (sum1 / n) * (sum1 / n) / sum2 * n;
                double r = sum1 / n;
                //方差不能太大，半径不能太小
                if (r>30&&fc<0.06)
                    GestureDetected(this, new GestureDetectedEventArgs(new CircleGesture(_currentContactId, o, null), 1));
                ULogger.Info(fc.ToString());
                ULogger.Info(r.ToString());
            }
                 
            _gesturePath.Clear();
        }
        #endregion

        #region Properties

        public double MaxTapDistance { get; set; }

        public bool TrackVelocity
        {
            get { return _physicsTracker.TrackVelocity; }
            set { _physicsTracker.TrackVelocity = value; }
        }

        public TimeSpan MaxDrawTime { get; set; }

        public OneContactCustomizedStateType State { get; set; }

        public List<OneContactCustomizedGestureType> EnabledGestures { get; set; }

        #endregion

        public OneContactCustomizedGestureRecognizer()
        {
            _contactNumberRange = new Range(1, 1);
            State = OneContactCustomizedStateType.Wait;
            _gesturePath = new List<Point>();
            // initialize the variables
            EnabledGestures = new List<OneContactCustomizedGestureType>();
            TrackVelocity = false;
            MaxDrawTime = TimeSpan.FromMilliseconds(2000);
        }

        #region GestureRecognizer Members

        public Range ContactNumberRange
        {
            get { return _contactNumberRange; }
        }

        public int Priority
        {
            get { return 10; }
        }

        public bool IsSupportedGesture(Type gesture)
        {
            return gesture.IsSubclassOf(typeof(OneContactCustomizedGesture));
        }

        public void StartRecognize(GestureInfo info)
        {
            Point p = (GestureEngine.TargetNode as UIElement).TranslatePoint(info.Contacts[0].CurrentPosition, GestureEngine.RelativeElement);
            _currentContactId = info.Contacts[0].ID;
            _startPosition = p;
            _gesturePath.Add(p);
            _FingerDownTimeTick = info.Contacts[0].CurrentTimestamp;
            State = OneContactCustomizedStateType.Proceed;
            // start the hold timer
            if (this.EnabledGestures.Count != 0)
            {
                _drawTimer = new DispatcherTimer();
                _drawTimer.Tick += new EventHandler(_drawTimer_Tick);
                _drawTimer.Interval = MaxDrawTime;
                _drawTimer.Start();
            }
        }

        public void Recognizing(GestureInfo info)
        {
            Point p = (GestureEngine.TargetNode as UIElement).TranslatePoint(info.Contacts[0].CurrentPosition, GestureEngine.RelativeElement);
            if (State == OneContactCustomizedStateType.Proceed)
            {
                _gesturePath.Add(p);                
            }            
        }

        public void EndRecognize(GestureInfo info)
        {
            Point p = (GestureEngine.TargetNode as UIElement).TranslatePoint(info.Contacts[0].CurrentPosition, GestureEngine.RelativeElement);
            if (State == OneContactCustomizedStateType.Proceed)
            {
                // stop drawtimer
                if (_drawTimer != null)
                {
                    _drawTimer.Stop();
                    _drawTimer = null;
                }

                TryRecognize();
            }
            State = OneContactCustomizedStateType.Wait;

        }

        public LocalGestureEngine GestureEngine { get; set; }

        public event GestureDetectedEventHandler GestureDetected;

        #endregion
    }

    public enum OneContactCustomizedGestureType
    {
        /// <summary>
        /// Raised when one finger down, and up after a circle is drawn
        /// </summary>
        Circle,
    }

    public class OneContactCustomizedGesture : Gesture
    {
        protected Point _position;
        protected int _contactID;

        public OneContactCustomizedGesture(int contactId, Point position)
        {
            _contactID = contactId;
            _position = position;
        }

        public Point Position { get { return _position; } }

        public int ContactID { get { return _contactID; } }
    }

    public class CircleGesture : OneContactGesture
    {
        public CircleGesture(int contactId, Point position, GestureInfo info)
            : base(contactId, position, info)
        {
        }

        public override string ToString()
        {
            return "Circle " + ContactID + ": " + Position;
        }
    }

    public enum OneContactCustomizedStateType
    {
        Proceed,
        Wait,
    }
}